<!-- directive:title 路由/树形结构 一级 ui-router 详解 -->
<!-- directive:breadcrumb 路由设置详解 -->
<div class='panel-body'>
    <div class='panel panel-default'>
        <div class='panel-heading'> 路由/树形结构 统一声明的写法 </div>
        <div class='panel-body'>
            <article class="docs-content">
                <p>拿项目结构作为例子</p>
                <script type="text/xianjs" ui-bs>
                    {abstract:true,page:99,root:10,name:'app',url:"/app:mid" },
                    {default :true,page:88,leaf:0 ,name:'app.selectMyStore',title:"我的门店",templateUrl:'store/MyStore2.html'},

                    {abstract:true,page:10,tree:12,name:'app.main',title:"会员服务",icon:1,power:"1" },
                    {default :true,page:10,leaf:12,name:'app.main.mainIndex',title:"工作台",power:"11"},
                    {              page:10,leaf:0 ,name:'app.main.mainIndex_ruchang',title:"入场"},
                    {              page:10,leaf:12,name:'app.main.write_Off',title:"充值消费",power:"12",url: "?card_no"},
                    {              page:10,leaf:0 ,name:'app.main.write_Off_new',title:"新增会员"},

                    {default :true,page:12,tree:35,name:'app.small_program',title:"微信授权",icon:6,templateUrl:'wx/small_program.html'},
                    {              page:12,leaf:0 ,name:'app.small_program_sq',templateUrl:'wx/small_program_sq.html',url:"?url"},
                    {              page:12,leaf:0 ,name:'app.small_program_version',templateUrl:'wx/small_program_version.html',url:"?appid&ID"},
                    {              page:12,leaf:0 ,name:'app.small_program_set',templateUrl:'wx/small_program_set.html',url:"?appid&status"},
                </script>
                <p>路由结构参数说明</p>
                <ul>
                    <li>abstract:true 抽象路径 <code>不能直接访问</code> 目的是建立父路由 </li>
                    <li>default :true 默认的首页 <code>注意如果有多个 选第一个</code></li>
                    <li>page:99 用于区分 行业/通用/未注册 等状态 (<code>99根状态</code>就是不管怎样都会加载) (<code>12未绑定appid</code>只加载'微信授权') (<code>10平凡模块</code>有appid就能加载) (<code>11通用模块</code>非行业模块就加载) (<code>38健身模块</code>是健身行业就加载) (<code>88多权限的选择</code>特殊定义的 配合权限一块用)</li>
                    <li>root:10 根 app 只会加载 不会显示</li>
                    <li>tree:12 树 通常代表一级节点 会渲染成树形目录的一级节点</li>
                    <li>leaf:12 叶子 通常代表二级节点 会渲染成树形目录的二级节点 他的值必须等于树的值 也必须放在树的下面</li>
                    <li>leaf:0 子页面 代表加载路由但是不渲染成树形目录 最好也放在树的下面</li>
                    <li>name: xxx.xxx.xxx 路由的名称 组成是 一级.二级.三级 最好不要搞四级 对应文件起名并且放置在 tpl.v2/二级/三级.HTML</li>
                    <li>templateUrl: xxx 如果实在是 文件路径和路由名字对不上 可以用这个改变设置</li>
                    <li>icon:1 树形目录的一级节点的logo 与css有对应</li>
                    <li>url: "?card_no" 如果需要传参 写成这样 参数值默认为null</li>
                    <li>power:12 权限 有权限12时候显示本节点 (一二级均可使用)</li>
                </ul>
                <p>路由结构规范以及目的</p>
                <ul>
                    <li>文件起名 尽量 尽量 尽量 短小精悍 别太长 ---目的是一屏幕显示的下</li>
                    <li>代码对齐 代码对齐 代码对齐 ---目的是方便区分块</li>
                    <li>文件路径 尽量 尽量 尽量 与路由一致 ---当然凡事有例外</li>
                    <li>如果需要一级节点可点击 不配置<code>abstract:true</code> 写上 <code>templateUrl</code></li>
                    <li>如果需要二级节点选中时候树形目录一级节点也点亮 可以写成 子页面名字中包含父页面名字</li>
                    <li>待续</li>
                </ul>
                <p></p>
                
            // name 和 url 要求保持一致
            // page 代表接受一级目录控制 
            // root/tree/leaf 代表路由层级关系
            </article>
        </div>
    </div>
    <hr />
    <uib-accordion>
        <uib-accordion-group heading="简介特性">
            <article class="docs-content">
                <p>UI-Router被认为是AngularUI为开发者提供的<code>最实用</code>的一个模块</p>
                <p>UI-Router作为web应用的依赖，注入到主程序：</p>
                <script type="text/xian" ui-bs>
                    angular.module('myApp', ['ui.router']);
                </script>
                <p>与集成的ngRoute服务不同的是，UI-Router可以将<code>视图嵌套</code>，因为它基于的是<code>操作状态</code>而仅非URL。</p>
                <p>与传统做法使用ng-view不同的是，在ngRoute里需要使用<code>ui-view</code>服务。</p>
                <p>要定义一个路由，与传统的方法相同：使用.config方式，但使用的不是$routeProvider而是<code>$stateProvider</code>。</p>
                <p>和ngRoute相似。</p>
                <p>开发者可以指定任何已经被注册的控制器，或者在路由里面创建一个作为控制器的函数。<code>但如果没有定义模板，控制器将无效。</code></p>
                <p>使用<code>预载入（resolve）</code>功能，开发者可以预先载入一系列依赖或者数据，然后注入到控制器中。</p>
                <p>在ngRoute中resolve选项可以允许开发者在路由到达前载入<code>数据保证</code>（promises）。ui-router也一样</p>
            </article>
        </uib-accordion-group>
        <uib-accordion-group heading="ui-sref 专题">
            <article class="docs-content">
                <p>页面传参 stateparam = {{stateparam}}</p>
                <p>测试跳转子页面 并且让左侧树选中</p>
                <p><a ui-sref="app.ng.uiroutersub">子路由 app.ng.uiroutersub [ui-sref="app.ng.uiroutersub"]</a></p>
                <p>跳转过程中传参</p>
                <p><a ui-sref="app.ng.uiroutersub({id:1,name:2})">子路由 app.ng.uiroutersub [ui-sref="app.ng.uiroutersub({id:1,name:2})"]</a></p>
                <p><a ui-sref="app.ng.uiroutersub({id:1,name:2})">子路由 app.ng.uiroutersub [ui-sref="app.ng.uiroutersub({id:1,name:2})"]</a></p>
                <p><a href="javascript:void(0)"><del>子路由 app.ng.uiroutersub [href="#!/app/ng/uiroutersub?id=1&name=2"] 这样也行不过禁止用</del></a></p>
                <p><a ui-sref="{{'null'}}">设置空值就不会跳转但是会报错了 [ui-sref="{{'null'}}"]</a></p>
                <p><a ui-sref="null">设置空值就不会跳转但是会报错了 [ui-sref="null"]</a></p>
                <p>
                    <del class="text-danger">急需研究搞定</del>
                    <span class="text-info">注册一个叫"null"的路由,在访问时候中止,这样就不报错了,先凑合吧</span>
                </p>
                <p><a ui-sref="app.ng.uirouter" ui-sref-opts="{reload:true}">强刷本页面 (或者叫状态) [ui-sref="app.ng.uirouter" ui-sref-opts="{reload:true}"]</a></p>
                <p>改变一级路由传参到还<a ui-sref="app.ng.uirouter({mid:3721})">简单(ui-sref="app.ng.uirouter({mid:3721})")</a></p>
                <p>现在需要一个更加强力的刷新逻辑, 目的是重新走一遍路由注册,<a ng-click="reloadme()">走你 (location.reload())</a></p>
            </article>
        </uib-accordion-group>
        <uib-accordion-group heading="ui-router 全部内容">
            <article class="docs-content">
                <p> <strong>ui-view</strong></p>
                <p>指示器：渲染状态中定义的视图，是状态中定义的视图的一个占位符。 </p>
                <p> <strong>$state / $stateProvider</strong></p>
                <p>状态类：管理状态定义、当前状态和状态转换。</p>
                <p>包含触发状态转换的事件和回调函数，异步解决目标状态的任何依赖项，更新<code>$location</code>到当前状态。由于状态包含关联的 url，通过$urlRouterProvider生成一个路由规则来执行转换的状态。 </p>
                <p> <strong>$urlRouter / $urlRouterProvider</strong></p>
                <p>路由类：管理了一套路由规则列表来处理当<code>$location</code>发生变化时如何跳转。最低级的方式是，规则可以是任意函数，来检查<code>$location</code>，并在处理完成时候返回<code>true</code>。支持正则表达式规则和通过<code>$urlMatcherFactory</code>编译的<code>UrlMatcher</code>对象的 url 占位符规则。 </p>
                <p> <strong>$urlMatcherFactory</strong></p>
                <p>匹配器：将 url和占位符编译为<code>UrlMatcher</code>对象。除了<code>$routeProvider</code>支持的占位符语法之外，它还支持扩展语法，允许一个正则表达式指定占位符，并且能够提取命名参数和查询url的一部分。 </p>
                <p> <strong>$templateFactory</strong></p>
                <p>通过<code>$http</code>&nbsp;/&nbsp;<code>$templateCache</code>来加载模板，供状态配置中使用。 </p>
            </article>
        </uib-accordion-group>
        <uib-accordion-group heading="路由配置url选项">
            <article class="docs-content">
                <p>url选项将会为该应用的状态指定一个URL基于用户浏览该应用所在的状态。</p>
                <p>URL参数有多个选项，因此它<code>非常强大</code>。开发者可以像设置ngRoute一样设置最基本的参数：</p>
                <p>访问/inbox/1,那么$stateParams.inboxId就为1（$stateParams为{inboxId:1}）</p>
                <p>路径同时也使开发者可以使用正则表达式来匹配</p>
                <script type="text/xian" ui-bs>
                    $stateProvider.state('home', {
                        url: '/inbox/:inboxId', // 或者 url: '/inbox/{inboxId}'
                        template: '<h1>Welcome to your inbox</h1>',
                        controller: function($scope, $stateParams) { x = $stateParams.inboxId; }
                    });
                    $stateProvider.state('home', {
                         // 限定id为6位16进制数字
                        url: '/inbox/{inboxId:[0-9a-fA-F]{6}}',
                        // 或者 匹配任何在 `/inbox`后面的url（慎用）并匹配值到indexId
                        url: '/inbox/{inboxId:.*}'
                    });
                </script>
                <p>onEnter,onExit 两个回调函数使开发者可以根据状态改变来采取某些动作，</p>
                <p>例如在<code>用户要离开时</code>可以弹出对话框‘你确定吗？’以及防止意外操作等。</p>
                <script type="text/xian" ui-bs>
                    $stateProvider.state('other',{
                        url: '/other/{name: [0-9]}',
                        params: { name: '', id: '' },
                        templateUrl: 'other.html',
                        controller: 'OtherController',
                        onEnter: function (){ console.log('enter'); },//进入页面时会走该方法
                        onExit: function (){ console.log('exit'); }//离开时走该方法
                    });
                </script>
            </article>
        </uib-accordion-group>
        <uib-accordion-group heading="路由改变监听事件">
            <script type="text/xian" ui-bs>
                //路由开始切换
                //args[0]: 事件 args[1]: 要切换的路由 args[2]: 第一次进入该方法,没有当前路由,为undefined
                $rootScope.$on('$routeChangeStart',function (event,next,current){
                    console.log([event,next,current]);
                });
                //路由切换成功
                $rootScope.$on('$routeChangeSuccess',function (event,current,previous){
                    console.log([event,current,previous]);
                });
                //路由切换失败(比如resolve中有错误等待),都会导致路由切换失败
                $rootScope.$on('$routeChangeError',function (event,msg){
                    console.log([event,msg]);
                });
                //当$location.path发生变化或者$location.url发生变化时触发
                $rootScope.$on('$locationChangeStart',function (event,msg){
                    console.log([event,msg]);
                });
                //当且仅当path或url变化成功后触发
                $rootScope.$on('$locationChangeSuccess',function (event,msg){
                    console.log([event,msg]);
                });
            </script>
        </uib-accordion-group>
        <uib-accordion-group heading="路由的 promise/数据保证">
            <article class="docs-content">
                <p>angular-route会试图匹配已经注册的服务。</p>
                <ul>
                    <li>如果传入的是函数，该函数将会被注入，并且该函数返回的值便是控制器的依赖之一。</li>
                    <li>如果该函数返回一个 promise ，这个 promise 将在<code>控制器被实例化前</code>被预先载入并且数据会被注入到控制器中。</li>
                </ul>
                <script type="text/xian" ui-bs>
                    $stateProvider.state('home', {
                        resolve: {
                            //这个函数的值会被直接返回，因为它不是数据保证
                            person: function() { return { name: "Ari", email: "ari@fullstack.io" } },
                            //这个函数为数据保证, 因此它将在控制器被实例化之前载入。
                            currentDetails: function($http) { return $http({ method: 'JSONP', url: '/current_details' }); },
                            //前一个数据保证也可作为依赖注入到其他数据保证中！（这个非常实用）
                            facebookId: function($http, currentDetails) {$http({ method: 'GET', url: '/current_details', params: { email: currentDetails.data.emails[0] } }) }
                        },
                        //定义控制器
                        controller: function($scope, person, currentDetails, facebookId) {}
                    })
                </script>
                <p></p>
                <p></p>
            </article>
        </uib-accordion-group>
        <uib-accordion-group heading="用url参数可以实现嵌套路由">
            <article class="docs-content">
                <p>第一个路由是传统的，注意第二个，它是/inbox下的一个子路由</p>
                <p>abstract 抽象模板 抽象模板不能被激活，但是它的子模板可以被激活。</p>
                <script type="text/xian" ui-bs>
                    $stateProvider
                    .state('inbox', {
                        abstract: true,
                        url: '/inbox/:inboxId',
                        template: '<div ui-view></div>'
                    })
                    .state('inbox.priority', {
                        url: '/priority',
                    });
                </script>
                <p>$stateParams 状态参数来提取在url中的不同参数。</p>
                <p>注意 另一个params选项是一个包含路径中的参数和正则表达式匹配结果的数组。<code>该选项不能和url选项混用！</code>当某状态被激活时，应用将这个数组赋值给$stateParams服务。</p>
                <p>每一级路由均可以接收参数</p>
                <script type="text/xian" ui-bs>
                    //配置信息
                    .state('inbox', {{url: '/inbox/:inboxId/messages/{sorted}?from&to'}
                    //当用户访问者链接时：
                    '/inbox/123/messages/ascending?from=10&to=20'
                    //获得信息
                    $stateParams = {inboxId: '123', sorted: 'ascending', from: 10, to: 20}
                </script>
                <h3 class="text-info">这个可以有效解决一个用户 (超管) 登录多个系统的问题</h3>
                <p><a class="btn btn-danger" href="#!/app/ng/uirouter/f/12/s/21">跳转</a></p>
                <div>result:<div ui-view></div></div>
            </article>
        </uib-accordion-group>
        <uib-accordion-group heading="状态改变事件">
            <article class="docs-content">
                <script type="text/xian" ui-bs>
                    $scope.$on('$stateChangeStart', function(evt, toState, toParams, fromState, fromParams), {
                        // 如果需要阻止事件的完成
                        evt.preventDefault();
                    });
                </script>
                <p><code>$stateChangeStart</code> 当状态改变开始的时候被触发</p>
                <p><code>$stateChangeSuccess</code> 当状态改变成功后被触发发</p>
                <p><code>$stateChangeError</code> 当状态改变遇到错误时被触发发</p>
                <p>使用场景通常是 <code>目标无法载入</code>，<code>用户无权查看想要页面</code>，<code>需要预载入的数据无法被载入等</code>。</p>
                <p></p>
            </article>
        </uib-accordion-group>
        <uib-accordion-group heading="设置多个有名称的视图">
            <article class="docs-content">
                <script type="text/xian" ui-bs>
                    <div>
                        <div ui-view="filters"></div>
                        <div ui-view="mailbox"></div>
                        <div ui-view="priority"></div>
                    </div>
                    $stateProvider .state('inbox', {
                        views: {
                            'filters': { template: '<h4>Filter inbox</h4>', controller: function($scope) {} },
                            'mailbox': { templateUrl: 'partials/mailbox.html' },
                            'priority': { template: '<h4>Priority inbox</h4>', resolve: { facebook: function() { return FB.messages(); } } }
                        }
                    });
                </script>
                <p>多模块同时更新 且互相不影响</p>
            </article>
        </uib-accordion-group>
        <uib-accordion-group heading="重定向或者安全验证">
            <article class="docs-content">
                <p>when() 该函数需要两个参数：1.当前的路径，2.需要重定向到的路径（或者是需要在路径被访问是运行的函数）。</p>
                <p>设置重定向前需要为$urlRouterProvider设置when函数来接受一个字符串。</p>
                <p>例如，当希望<code>重定向一个空的路由</code>到/inbox：</p>
                <script type="text/xian" ui-bs>
                    $urlRouterProvider.when('', '/inbox');
                </script>
                <p>otherwise() 在用户提交的路径没有被定义的时候它将重定向到指定的页面。</p>
                <p><code>这是个创建’默认‘路径的好方法。</code> </p>
                <p>otherwise()只接受一个参数，要么函数要么字符串，字符串必须为合法的url路由地址，函数则会在没有任何路径被匹配的时候被运行。</p>
                <script type="text/xian" ui-bs>
                    $urlRouterProvider.otherwise('/');
                    $urlRouterProvider.otherwise( function($injector, $location) { $location.path('/'); });
                </script>
                <p>rule() 如果想越过任何URL的匹配或者在其他路由前做路由修改，则可以使用rule()函数。</p>
                <p>在使用它的时候必须返回一个<code>合法的代表路径</code>的字符串。</p>
                <script type="text/xian" ui-bs>
                    $urlRouterProvider.rule( function($injector, $location) { return '/index'; });
                </script>
            </article>
        </uib-accordion-group>
    </uib-accordion>
</div>

